package com.cskaoyan.wordmemorize.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cskaoyan.wordmemorize.common.constant.ResultCodeEnum;
import com.cskaoyan.wordmemorize.common.exception.BusinessException;
import com.cskaoyan.wordmemorize.converter.EmployeeConverter;
import com.cskaoyan.wordmemorize.dao.entity.*;
import com.cskaoyan.wordmemorize.dao.mapper.*;
import com.cskaoyan.wordmemorize.dto.admin.DeleteEmployeeRoleOperateDTO;
import com.cskaoyan.wordmemorize.dto.admin.EmployeeDTO;
import com.cskaoyan.wordmemorize.dto.admin.PageDTO;
import com.cskaoyan.wordmemorize.request.EmployeeCommand;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

// todo 【后台管理-账号权限管理-员工管理】
@Service
public class EmployeeServiceImpl implements EmployeeService {


    @Autowired
    EmployeeMapper employeeMapper;

    @Autowired
    EmployeeConverter employeeConverter;

    @Autowired
    EmployeeRoleMapper employeeRoleMapper;

    @Autowired
    RoleMapper roleMapper;
    @Autowired
    private RolePermissionMapper rolePermissionMapper;
    @Autowired
    private PermissionMapper permissionMapper;


    @Override
    public EmployeeDTO login(String userName, String password) {

        // 1. 将明文密码变为密文密码
        String encodePassword = SaSecureUtil.md5(password);

        // 2. 根据用户名和密码查询数据库
        LambdaQueryWrapper<EmployeeDO> employeeWrapper = new LambdaQueryWrapper<>();
        employeeWrapper.eq(EmployeeDO::getName, userName)
                .eq(EmployeeDO::getPassword, encodePassword);

        EmployeeDO employeeDO = employeeMapper.selectOne(employeeWrapper);
        if (employeeDO == null) {
            throw new BusinessException(ResultCodeEnum.LOCAL_LOGIN_FAIL);
        }


        return employeeConverter.employeeDO2DTO(employeeDO);
    }

    @Override
    public EmployeeDTO getEmployeeInfo(Long employeeId) {


        EmployeeDO employeeInfo = employeeMapper.getEmployeeInfo(employeeId);
        return employeeConverter.employeeDO2DTO(employeeInfo);
    }

    // todo 获取后台员工列表
    @Override
    public PageDTO<EmployeeDTO> getEmployeePage(PageRequest request) {

        // todo 不分页
        if(request.getPageNum() == null){
            List<EmployeeDO> employeeDOs = employeeMapper.selectList(null);
            for(EmployeeDO employeeDO : employeeDOs) {
                List<Long> roleIds = employeeMapper.getRoleIds(employeeDO.getId()).stream().distinct().collect(Collectors.toList());
                List<String> perms = employeeMapper.getPerms(employeeDO.getId()).stream().distinct().collect(Collectors.toList());
                employeeDO.setRoleIds(roleIds);
                employeeDO.setPerms(perms);
            }
            return employeeConverter.emoloyeePage2PageDTO(employeeDOs, (long) employeeDOs.size());
        }

        // todo 分页
        Page<EmployeeDO> pageParam = new Page<>(request.getPageNum(), request.getCount());
        LambdaQueryWrapper<EmployeeDO> wrapper = new LambdaQueryWrapper<>();
        if (request.getKeyword() != null) {
            wrapper.like(EmployeeDO::getName, request.getKeyword());
            wrapper.or();
            wrapper.like(EmployeeDO::getNickName, request.getKeyword());
        }
        Page<EmployeeDO> employeeDOs = employeeMapper.selectPage(pageParam, wrapper);
        for(EmployeeDO employeeDO : employeeDOs.getRecords()){
            List<Long> roleIds = employeeMapper.getRoleIds(employeeDO.getId()).stream().distinct().collect(Collectors.toList());
            List<String> perms = employeeMapper.getPerms(employeeDO.getId()).stream().collect(Collectors.toList());
            employeeDO.setRoleIds(roleIds);
            employeeDO.setPerms(perms);
        }
        return employeeConverter.emoloyeePage2PageDTO(employeeDOs.getRecords(), employeeDOs.getTotal());

    }
    // todo 添加后台员工
    @Override
    @Transactional
    public void addEmployee(EmployeeCommand command) {
        // todo 校验必填字段
        if (StringUtils.isBlank(command.getName())) {
            throw new BusinessException(ResultCodeEnum.PARAM_ERROR);
        }
        if (StringUtils.isBlank(command.getPassword())) {
            throw new BusinessException(ResultCodeEnum.PARAM_ERROR);
        }

        // todo 检查用户名是否已存在
        LambdaQueryWrapper<EmployeeDO> usernameWrapper = new LambdaQueryWrapper<>();
        usernameWrapper.eq(EmployeeDO::getName, command.getName());
        if (employeeMapper.selectCount(usernameWrapper) > 0) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }

        // todo 检查手机号是否已存在（如果有手机号）
        if (StringUtils.isNotBlank(command.getPhoneNumber())) {
            LambdaQueryWrapper<EmployeeDO> phoneWrapper = new LambdaQueryWrapper<>();
            phoneWrapper.eq(EmployeeDO::getPhoneNumber, command.getPhoneNumber());
            if (employeeMapper.selectCount(phoneWrapper) > 0) {
                throw new BusinessException(ResultCodeEnum.FAIL);
            }
        }

        // todo 密码加密
        command.setPassword(SaSecureUtil.md5(command.getPassword()));

        // todo 保存员工基本信息
        EmployeeDO newEmployee = employeeConverter.command2EmployeeDO(command);
        employeeMapper.insert(newEmployee);

        // todo 处理角色关联（如果有）
        if (command.getRoleIds() != null && !command.getRoleIds().isEmpty()) {
            command.getRoleIds().stream()
                    .map(Long::valueOf)
                    .forEach(roleId -> {
                        EmployeeRoleDO er = new EmployeeRoleDO();
                        er.setEmployeeId(newEmployee.getId()); // 使用生成的ID
                        er.setRoleId(roleId);
                        employeeRoleMapper.insert(er);
                    });
        }

    }

    @Override
    @Transactional
    public void updateEmployee(EmployeeCommand command) {
        // todo 验证员工是否存在
        EmployeeDO existingEmployee = employeeMapper.selectById(command.getId());
        if (existingEmployee == null) {
            throw new BusinessException(ResultCodeEnum.EMPLOYEE_NOT_EXIST);
        }

        // todo 更新员工基本信息
        EmployeeDO updateEmployee = new EmployeeDO();
        updateEmployee.setId(Long.valueOf(command.getId()));

        // todo 只更新非空字段
        if (StringUtils.isNotBlank(command.getName())) {
            updateEmployee.setName(command.getName());
        }
        if (StringUtils.isNotBlank(command.getNickName())) {
            updateEmployee.setNickName(command.getNickName());
        }
        if (StringUtils.isNotBlank(command.getPhoneNumber())) {
            updateEmployee.setPhoneNumber(command.getPhoneNumber());
        }
        if (StringUtils.isNotBlank(command.getAvatar())) {
            updateEmployee.setAvatar(command.getAvatar());
        }
        if (StringUtils.isNotBlank(command.getPassword())) {
            updateEmployee.setPassword(SaSecureUtil.md5(command.getPassword()));
        }

        employeeMapper.updateById(updateEmployee);

        // todo 处理角色关联（仅新增）
        if (command.getRoleIds() != null && !command.getRoleIds().isEmpty()) {
            // 获取现有角色
            List<Long> existingRoles = employeeRoleMapper.selectList(
                            new LambdaQueryWrapper<EmployeeRoleDO>()
                                    .eq(EmployeeRoleDO::getEmployeeId, command.getId()))
                    .stream()
                    .map(EmployeeRoleDO::getRoleId)
                    .collect(Collectors.toList());

            // 找出需要新增的角色
            command.getRoleIds().stream()
                    .map(Long::valueOf)
                    .filter(roleId -> !existingRoles.contains(roleId))
                    .forEach(roleId -> {
                        EmployeeRoleDO er = new EmployeeRoleDO();
                        er.setEmployeeId(Long.valueOf(command.getId()));
                        er.setRoleId(roleId);
                        employeeRoleMapper.insert(er);  // 单条插入
                    });
        }
    }

    // todo 后台删除员工信息---删除指定员工(后台账号权限管理-员工管理)
    @Override
    public void delete(Long employeeId) {

        // 用条件构造器找到对应ID的DO，然后用mapper删除
        LambdaQueryWrapper<EmployeeDO> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();

        objectLambdaQueryWrapper.eq(EmployeeDO::getId, employeeId);

        employeeMapper.delete(objectLambdaQueryWrapper);
    }


    // todo 后台删除员工-员工关联信息---删除指定员工的角色(后台账号权限管理-员工管理)
    @Override
    public DeleteEmployeeRoleOperateDTO deleteRole(Long employeeId, Long roleId) {

        // 通过条件构造器找到对应的 EmployeeRoleDO 对象
        LambdaQueryWrapper<EmployeeRoleDO> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(EmployeeRoleDO::getEmployeeId, employeeId);
        lambdaQueryWrapper.eq(EmployeeRoleDO::getRoleId, roleId);

        // employeeRoleMapper 通过继承关系已经锁定数据表，然后删除
        employeeRoleMapper.delete(lambdaQueryWrapper);

        // 删除时，EmployeeDO 和 RoleDO 肯定已经存在，分别把它们找出来
        // 找EmployeeDO
        EmployeeDO employeeDO = employeeMapper.selectById(employeeId);

        // 找RoleDO
        RoleDO roleDO = roleMapper.selectById(roleId);

        // 用EmployeeDO 和 RoleDO 合成 DeleteEmployeeRoleOperateDTO
        DeleteEmployeeRoleOperateDTO deleteEmployeeRoleOperateDTO = employeeConverter.toDeleteEmployeeRoleOperateDTO(employeeDO,roleDO);

        return deleteEmployeeRoleOperateDTO;
    }

    @Override
    public void updateLoginInfo(Long employeeId, String ip, LocalDateTime time) {

        EmployeeDO employeeDO = new EmployeeDO();
        employeeDO.setId(employeeId);
        employeeDO.setLastLoginIp(ip);
        employeeDO.setLastLoginTime(time);

        employeeMapper.updateById(employeeDO);
    }

    @Override
    public Set<String> getPermissionAlias(Long employeeId) {

        return employeeMapper.getPermissionAliases(employeeId).stream().filter(alias -> alias != null && alias.startsWith("admin")).collect(Collectors.toSet());
    }

    @Override
    public boolean saveBatch(Collection<EmployeeDO> entityList, int batchSize) {
        return false;
    }

    @Override
    public boolean saveOrUpdateBatch(Collection<EmployeeDO> entityList, int batchSize) {
        return false;
    }

    @Override
    public boolean updateBatchById(Collection<EmployeeDO> entityList, int batchSize) {
        return false;
    }

    @Override
    public boolean saveOrUpdate(EmployeeDO entity) {
        return false;
    }

    @Override
    public EmployeeDO getOne(Wrapper<EmployeeDO> queryWrapper, boolean throwEx) {
        return null;
    }

    @Override
    public Optional<EmployeeDO> getOneOpt(Wrapper<EmployeeDO> queryWrapper, boolean throwEx) {
        return Optional.empty();
    }

    @Override
    public Map<String, Object> getMap(Wrapper<EmployeeDO> queryWrapper) {
        return null;
    }

    @Override
    public <V> V getObj(Wrapper<EmployeeDO> queryWrapper, Function<? super Object, V> mapper) {
        return null;
    }

    @Override
    public BaseMapper<EmployeeDO> getBaseMapper() {
        return null;
    }

    @Override
    public Class<EmployeeDO> getEntityClass() {
        return null;
    }
}
